package org.example.distributedlock;

import lombok.extern.slf4j.Slf4j;
import org.example.config.ApplicationContextHolder;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;

import java.util.concurrent.TimeUnit;

@Slf4j
public class RedisLockUtil {

    /**
     *
     * @param redissonInterface 业务实现类
     * @param key				缓存Key
     * @param waitTime			 锁超时，再次竞争锁的等待时间（单位：秒），<=0没有超时等待
     * @param leaseTime		缓存失效时间（单位：秒）
     */
    /*public static Object Lock(RedissonInterface<?> redissonInterface, String key, long waitTime, long leaseTime) {
        RLock rlock = null;
        try{
            RedissonClient redissonClient = ApplicationContextHolder.getBean(RedissonClient.class);
            //调用业务实现
            rlock = redissonClient.getLock(key);
            //boolean locked = rlock.isLocked();
            //是否加过锁
            if (rlock.tryLock(waitTime, leaseTime, TimeUnit.SECONDS)){
                System.out.println("上锁成功");
            //自己加的
            }else{
                System.out.println("已上锁，不能重复操作");
                return false;
            }
            return redissonInterface.execute();
        } catch(Exception e){
            e.printStackTrace();
        } finally {
            //是加锁的那个线程才能释放锁 其他线程不需要释放锁 解决一直以来的疑惑 加rlock.isHeldByCurrentThread()这句
            //哪个线程加锁成功 就由哪个线程释放锁就对了 其他线程不用操作unlock了
            //还是不能释放 释放了就三个线程都会成功获取锁
            //if (rlock != null && rlock.isHeldByCurrentThread()){
            //    rlock.unlock();
            //}
        }
        return null;
    }*/

    /**
     * 这个分布式锁根据抖音蜗牛哥的代码写的
     * @param redissonInterface
     * @param key
     * @param waitTime
     * @param leaseTime
     * @return
     */
    public static Object Lock(RedissonInterface<?> redissonInterface, String key, long waitTime, long leaseTime) {
        RLock rlock = null;
        boolean locked = false;
        try{
            RedissonClient redissonClient = ApplicationContextHolder.getBean(RedissonClient.class);
            //调用业务实现
            rlock = redissonClient.getLock(key);
            //尝试抢占锁 tryLock中waitTime和leaseTime都是-1
            locked = rlock.tryLock(); //public boolean tryLock(long waitTime, TimeUnit unit)
            if(!locked){
                System.out.println("已上锁，不能重复操作");
                return false;
            }
            //拿到锁以后设置过期时间
            rlock.lock(leaseTime, TimeUnit.SECONDS);
            System.out.println("上锁成功");
            return redissonInterface.execute();
        } catch(Exception e){
            e.printStackTrace();
        } finally {
            //拿到锁的线程再释放锁
            if (locked && rlock.isHeldByCurrentThread()){
                rlock.unlock();
            }
        }
        return null;
    }
}
